package org.liquidByte.trafficMustang.androidApp.proxy;

import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;

import com.google.gson.Gson;
import com.google.gson.JsonIOException;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSyntaxException;

public abstract class Proxy {
	private static CookieStore cookieStore;
	private Gson gson;

	
	public synchronized static void cleanUp() {
		Proxy.cookieStore = null;
	}
	private synchronized static CookieStore getCookieStore() {
		if (Proxy.cookieStore == null) {
			Proxy.cookieStore = new BasicCookieStore();
		}
		return Proxy.cookieStore;
	}
	private static HttpClient newClient() {
		DefaultHttpClient client = new DefaultHttpClient();
		client.getParams().setParameter(ClientPNames.COOKIE_POLICY, ProxyConfig.getInstance().getCookiePolicy());
		client.setCookieStore(Proxy.getCookieStore());
		return client;
	}

	private Gson getGson() {
		if (this.gson == null) {
			this.gson = new Gson();
		}
		return this.gson;
	}
	
	protected <T> T invoke(String method, Class<T> expectedReturn) throws ProxyRuntimeException, RemoteException {
		ProxyRequestBuilder builder = new ProxyRequestBuilder();
		builder.setMethod(method);
		HttpUriRequest request = builder.build();
		String jsonData = this.doRequest(request);
		
		try {
			return this.getGson().fromJson(jsonData, expectedReturn);
		} catch (JsonParseException e) {
			throw new ProxyRuntimeException(e);
		}
	}
	
	protected void invoke(String method) throws ProxyRuntimeException, RemoteException {
		ProxyRequestBuilder builder = new ProxyRequestBuilder();
		builder.setMethod(method);
		HttpUriRequest request = builder.build();
		this.doRequest(request);
		
	}
	
	protected void invoke(String method, Object params) throws ProxyRuntimeException, RemoteException {
		ProxyRequestBuilder builder = new ProxyRequestBuilder();
		builder.setMethod(method);
		builder.setParam(params);
		HttpUriRequest request = builder.build();
		this.doRequest(request);
	}
	
	protected <T> T invoke(String method, Class<T> expectedReturn, Object params) throws ProxyRuntimeException, RemoteException {
		ProxyRequestBuilder builder = new ProxyRequestBuilder();
		builder.setMethod(method);
		builder.setParam(params);
		HttpUriRequest request = builder.build();
		String jsonData = this.doRequest(request);
		
		try {
			return this.getGson().fromJson(jsonData, expectedReturn);
		} catch (JsonParseException e) {
			throw new ProxyRuntimeException(e);
		}
	}
	
	private String doRequest(HttpUriRequest request) throws ProxyRuntimeException, RemoteException {
		HttpResponse response;

		try {
			HttpClient client = Proxy.newClient();
			response = client.execute(request);
		} catch (ClientProtocolException e) {
			throw new ProxyRuntimeException(e);
		} catch (IOException e) {
			throw new ProxyRuntimeException(e);
		}
		
		try {
			ResultMessage result = this.getGson().fromJson(new InputStreamReader(response.getEntity().getContent()), ResultMessage.class);
			if (result.hasError()) {
				throw RemoteException.fromError(result.getError());
			}
			
			return result.getJsonData();
		} catch (JsonSyntaxException e) {
			throw new ProxyRuntimeException(e);
		} catch (JsonIOException e) {
			throw new ProxyRuntimeException(e);
		} catch (IllegalStateException e) {
			throw new ProxyRuntimeException(e);
		} catch (IOException e) {
			throw new ProxyRuntimeException(e);
		}		
	}
	
	public static URI encodeUri(String method) {
		if (method == null || method == "") {
			return null;
		} else {
			try {
				return new URI(ProxyConfig.getInstance().getContextRoot() +
							  (!ProxyConfig.getInstance().getContextRoot().endsWith("/") && !method.startsWith("/") ? "/" : "") +
							   method);
			} catch (URISyntaxException e) {
				return null;
			}
		}
	}
}
